package ai4games_tests.tests;


import game2dai.World;
import game2dai.Domain;
import game2dai.entities.Building;
import game2dai.entities.Obstacle;
import game2dai.entities.Vehicle;
import game2dai.entityshapes.ps.BuildingPic;
import game2dai.entityshapes.ps.Hints;
import game2dai.entityshapes.ps.PersonPic;
import game2dai.entityshapes.ps.Umbrella;
import game2dai.graph.Graph;
import game2dai.graph.GraphNode;
import game2dai.maths.Vector2D;
import game2dai.steering.AutoPilot;
import game2dai.steering.SBF;
import game2dai.utils.StopWatch;
import processing.core.PApplet;

public class Demo_001 extends PApplet{
	World world;
	Domain wd;

	Building[] buildings;
	Obstacle[] stalls;
	Vehicle[] tourists;
	Vehicle[] patrol;
	Graph routes;
	GraphNode[] nodes;
	GraphNode dest = null;

	int[] stallCol1, stallCol2;

	StopWatch sw;

	Vector2D worldMouse = new Vector2D();

	int partSize = 100, partOverlap = 40;

	public void setup(){
		size(700,600);
		cursor(CROSS);
		stallCol1 = new int[] { color(174,44,79), color(255,227,40) };
		stallCol2 = new int[] { color(1,8,99), color(251,190,37), color(228,4,4), color(14,143,86) };

		world = new World(width, height, partSize, partOverlap);
//		world = new World(width, height);

		world.noOverlap(true);
		wd = new Domain(0, 0, width, height);

//		world.panPixelXY(10, 30);
		world.scale(0.6f);

		// Get the navigation map
		routes = Graph.makeFromXML(this, "ai4g/d001_graph.xml");
		nodes = routes.getNodeArray();
		// Create the buildings
		buildings = Building.makeFromXML(this, "ai4g/d001_buildings.xml");
		for(Building b : buildings){
			BuildingPic bpic = new BuildingPic(this, color(200,96,96), color(0), 4.0f);
			b.renderer(bpic);
			world.add(b);
		}
		// Create the market stalls (round bits)
		stalls = Obstacle.makeFromXML(this, "ai4g/d001_obstacles.xml");
		for(Obstacle stall : stalls){
			Umbrella opic = new Umbrella(this, stall.colRadius(), stallCol1);
			stall.renderer(opic);
			world.add(stall);
		}
		// Create all the moving objects - start with the patrol
		AutoPilot sb = new AutoPilot();	// steering behaviour used as base for others
		sb.wallAvoidFactors(3, 20, 2.8, true);
		sb.wallAvoidOn().obstacleAvoidOn();

		// Create the patrol
		patrol = Vehicle.makeFromXML(this, "ai4g/d001_patrol.xml");
		for(int i = 0;  i < patrol.length; i++){
			PersonPic apic = new PersonPic(this, 10, color(160,160,255), color(160,144,70), color(0), 1);
			AutoPilot patrolSB = (AutoPilot) sb.clone();
			if(i == 0){
				apic.bodyFill(color(100,100,255));
				patrolSB.pathOn().arriveWeight(900);
			}
			else {
				patrolSB.offsetPursuitOn(patrol[0], Vector2D.sub(patrol[i].pos(), patrol[0].pos()));
				patrolSB.offsetPursuitWeight(30);
			}
			patrol[i].AP(patrolSB);
			patrol[i].renderer(apic);
			patrol[i].worldDomain(wd);
			world.add(patrol[i]);
		}
		// Now create the tourist
		sb.wanderFactors(70, 10, 1000);
		AutoPilot touristSB = (AutoPilot) sb.clone();
		touristSB.wanderOn();
		touristSB.wanderFactors(70, 10, 10);
		touristSB.wallAvoidFactors(3, 20, 2.8, true);

		tourists = Vehicle.makeFromXML(this, "ai4g/d001_people.xml");
		for(Vehicle tourist : tourists){
			PersonPic apic = new PersonPic(this, 10, color(255,160,255), color(145,64,47), color(0), 1);
			tourist.maxForce(500);
			tourist.AP((AutoPilot) touristSB.clone());
			tourist.renderer(apic);
			tourist.worldDomain(wd);
			world.add(tourist);
		}
		setHints(false);
		sw = new StopWatch(); // last thing to be done in setup
	}

	public void draw(){
		float deltaTime = (float) sw.getElapsedTime();
		world.update(deltaTime);
		background(220);
		pushMatrix();
		translate((float)world.xOffset(), (float)(world.yOffset()));
		scale((float) world.scale());
		showNodes();
		if(!patrol[0].AP().isPathOn())
			patrol[0].velocity(0,0);
		world.draw();
		showPartitions();
		popMatrix();
//		noFill();
//		stroke(0);
//		strokeWeight(1.2f);
	}

	public void mouseMoved(){
		world.pixel2world(mouseX, mouseY, worldMouse);
		dest = routes.getNodeNear(worldMouse.x, worldMouse.y, 0, 16);

		BuildingPic bpic;
		for(Building b : buildings){
			bpic = (BuildingPic) b.renderer();
			if(b.isOver(worldMouse.x, worldMouse.y))
				bpic.fill(color(128,0,0));
			else
				bpic.fill(color(0,128,0));
		}

		Umbrella opic;
		for(Obstacle stall : stalls){
			opic = (Umbrella) stall.renderer();
			if(stall.isOver(worldMouse.x, worldMouse.y))
				opic.setFill(stallCol1);
			else
				opic.setFill(stallCol2);
		}
	}

	public void mouseClicked(){
		if(dest != null)
			patrol[0].AP().pathAddToRoute(routes, dest);
	}

	public void showNodes(){
		pushStyle();
		noStroke();
		int r;
		ellipseMode(CENTER);
		for(GraphNode node : nodes){
			if(dest == null || dest != node){
				r = 8;
				fill(0,200,0);
			}
			else {
				r = 24;
				fill(0,128,0);
			}
			ellipse(node.xf(), node.yf(), r, r);
		}
		popStyle();
	}

	public void showPartitions(){
		noFill();
		stroke(255,255,0,128);
		strokeWeight(1.0f);
		int p = 0;
		int d = max(width, height);
		while(p <= d){
			line(0, p, width, p);
			line(p, 0, p, height);
			p += partSize;
		}
	}

	public void setHints(boolean showHints){
		for(Vehicle tourist : tourists)
			((PersonPic)tourist.renderer()).showHints(Hints.HINT_HEADING | Hints.HINT_VELOCITY);
		for(Vehicle patrolman : patrol)
			((PersonPic)patrolman.renderer()).showHints(Hints.HINT_HEADING | Hints.HINT_VELOCITY);
		for(Obstacle stall : stalls)
			((Umbrella)stall.renderer()).showHints(Hints.HINT_COLLISION);
	}
}
